﻿// <copyright file="CachableXmlConfigRepository.cs" company="IMIP">
// Copyright (c) 2010 IMIP. All Right Reserved.
// </copyright>
// <author>Huydq</author>
// <email>quanghuyqn@gmail.com</email>
// <date>14-Oct-09</date>
// <summary>Implement method to get config data from xml file. </summary>

using System;
using System.IO;
using System.Web;
using CommerceOne.Common.Configs;
using Microsoft.Practices.EnterpriseLibrary.Caching;
using Microsoft.Practices.EnterpriseLibrary.Caching.Expirations;

namespace Cooking.WidgetController.Configs
{
    /// <summary>
    /// Tien 19-May: XML configuration repository with caching support, utilized Enterprise Library Caching AB.
    /// Tien 31-Jul: Refactor to make it more loosely coupled with other classes/services.
    /// - Get widget configuration from Application state.
    /// - Using new IFileSystem for file manipulation.
    /// - Using new XmlReader/Writer factories for XML serialization.
    /// Tien 03-Aug: Refactor to use new IXmlSerializer.
    /// Tien 01-Oct: Refactor, remove parameterless constructor.
    /// </summary>
    public class CachableXmlConfigRepository : IWidgetConfigRepository
    {
        private IConfigurationManager configuration = null;
        private HttpContextBase httpContext = null;
        private ICacheManager cache = null;
        private IFileSystem file = null;
        private IXmlSerializer serializer = null;

        public ICacheItemExpiration CacheExpiration { get; set; }

#if CACHELOG
        private Logger log = null;
#endif
        /// <summary>
        /// Initializes a new instance of the CachableXmlConfigRepository class.
        /// </summary>
        /// <param name="context">Using HttpContextBase.</param>
        /// <param name="config">Using IConfiguration.</param>
        public CachableXmlConfigRepository(HttpContextBase context, IConfigurationManager config, ICacheManager cacheManager, IXmlSerializer serializer, IFileSystem file)
        {
            this.httpContext = context;
            this.configuration = config;
            this.cache = cacheManager;
            this.file = file;
            this.serializer = serializer;
        }

        #region IWidgetConfigRepository Members

        /// <summary>
        /// Tien 26-Jun: Add log for debugging.
        /// </summary>
        /// <param name="configName"></param>
        /// <param name="configType"></param>
        /// <param name="useCache"></param>
        /// <returns></returns>
        public IWidgetConfig GetConfigData(string configName, Type configType, bool useCache)
        {
            IWidgetConfig config = null;
            WidgetConfiguration widgetConfiguration = (WidgetConfiguration)httpContext.Application["WidgetConfiguration"];

#if CACHELOG
            log = new Logger();
            log.Log(string.Format("GetConfigData: {0}.", configName));
#endif
            if (useCache)
            {
                config = LoadCachedData(configName);

                if (null == config)
                {
#if CACHELOG
                    log.Log(string.Format("{0} is not cached.", configName));
#endif
                    string filePath = widgetConfiguration.GetConfigFilePath(configName);
                    config = LoadDataIntoCache(configName, configType, filePath);
                }

                return config;
            }

            return LoadDataFromFile(configType, widgetConfiguration.GetConfigFilePath(configName));
        }

        public IWidgetConfig GetConfigData(string configName, Type configType, ICacheItemExpiration expiration)
        {
            IWidgetConfig config = null;
            WidgetConfiguration widgetConfiguration = (WidgetConfiguration)httpContext.Application["WidgetConfiguration"];

#if CACHELOG
            log = new Logger();
            log.Log(string.Format("GetConfigData: {0}.", configName));
#endif

            config = LoadCachedData(configName);

            if (null == config)
            {
#if CACHELOG
                    log.Log(string.Format("{0} is not cached.", configName));
#endif
                string filePath = widgetConfiguration.GetConfigFilePath(configName);
                config = LoadDataIntoCache(configName, configType, filePath);
            }

            return config;
        }

        /// <summary>
        /// Get config data.
        /// </summary>
        /// <param name="configName"></param>
        /// <param name="configType"></param>
        /// <returns></returns>
        public IWidgetConfig GetConfigData(string configName, Type configType)
        {
            return GetConfigData(configName, configType, true);
        }

        /// <summary>
        /// Save config data to file.
        /// </summary>
        /// <param name="configName"></param>
        /// <param name="configObject"></param>
        /// <param name="configType"></param>
        public void SetConfigData(string configName, IWidgetConfig configObject, Type configType)
        {
            WidgetConfiguration widgetConfiguration = (WidgetConfiguration)httpContext.Application["WidgetConfiguration"];
            string filePath = widgetConfiguration.GetConfigFilePath(configName);

            if (!file.Exists(filePath))
                throw new FileNotFoundException();

            file.SetAttributes(filePath, FileAttributes.Normal);

            serializer.Serialize(filePath, configObject);
        }

        #endregion

        /// <summary>
        /// Load config data from cache.
        /// </summary>
        /// <param name="configName"></param>
        /// <returns></returns>
        private IWidgetConfig LoadCachedData(string configName)
        {
            return (IWidgetConfig)cache.GetData(configName);
        }

        /// <summary>
        /// Save config data into cache.
        /// </summary>
        /// <param name="configName"></param>
        /// <param name="configType"></param>
        /// <returns></returns>
        private IWidgetConfig LoadDataIntoCache(string configName, Type configType, string filePath)
        {
            IWidgetConfig config = LoadDataFromFile(configType, filePath);

            FileDependency fileDependency = new FileDependency(filePath);

            if (null != config)
            {
                cache.Add(configName, config, CacheItemPriority.Normal, null, fileDependency);
                CacheExpiration = fileDependency;
            }

            return config;
        }

        private IWidgetConfig LoadDataIntoCache(string configName, Type configType, string filePath, ICacheItemExpiration exp)
        {
            IWidgetConfig config = LoadDataFromFile(configType, filePath);

            FileDependency fileDependency = new FileDependency(filePath);

            if (null != config)
            {
                cache.Add(configName, config, CacheItemPriority.Normal, null, new ICacheItemExpiration[] { fileDependency, exp });
                CacheExpiration = fileDependency;
            }

            return config;
        }

        /// <summary>
        /// Tien 03-Aug: Refactored.
        /// </summary>
        /// <param name="configName"></param>
        /// <param name="configType"></param>
        /// <returns></returns>
        private IWidgetConfig LoadDataFromFile(Type configType, string filePath)
        {
            if (!file.Exists(filePath))
                throw new FileNotFoundException();
            return (IWidgetConfig)serializer.Deserialize(filePath, configType);
        }
    }
}